

import React, { useImperativeHandle, useRef, useState } from 'react';

import MonacoEditor from 'react-monaco-editor';
// 按需引入
import 'monaco-editor/esm/vs/basic-languages/java/java.contribution';
import 'monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution';
import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution';

// 主题颜色

// import 'monaco-editor/esm/vs/editor/contrib/find/browser/findController'; // 搜索控件

// 全量引入
import * as monaco from 'monaco-editor';

import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';

import { formatCodeByLanguage } from '@/utils/FormatterUtil';
import { useMount } from 'ahooks';
import { Spin } from 'antd';
import { useCallback, useEffect } from 'react';
import {
  IEditorMonacoProps,
  IEditorOperateEvent,
  IEditorRefHandles,
} from './CodeEditorConfig';
import { EditorContainerLayout } from './CodeEditorStyle';
import { resetEditorPosition } from './CodeEditorUtil';
import RegisterCompletion from './RegisterCompletion';

self.MonacoEnvironment = {
  getWorker(_, label) {
    if (label === 'json') {
      return new JsonWorker();
    }
    if (label === 'css' || label === 'scss' || label === 'less') {
      return new CssWorker();
    }
    if (label === 'html' || label === 'handlebars' || label === 'razor') {
      return new HtmlWorker();
    }
    if (label === 'typescript' || label === 'javascript') {
      return new TsWorker();
    }

    return new EditorWorker();
  },
};

type IEditorEntity = monaco.editor.IStandaloneCodeEditor;

interface Props extends IEditorMonacoProps {}

export const CodeEditorMonaco: React.FC<Props> = (props) => {
  const {
    handleRef,
    value,
    language = 'sql',
    theme,
    fontSize = 14,
    readOnly = false,
    format,
    onChange,
    saveChange,
    completers,
    onLoad,
    ...rest
  } = props;

  const [code, setCode] = useState(value);
  const [loading, setLoading] = useState<boolean>(false);

  // 编辑器实例化对象
  const editorRef = useRef<IEditorEntity>(); // 编辑器实例

  /**
   * 获取光标位置
   * @param editor
   * @returns
   */
  const getMonacoRange = (editor: IEditorEntity) => {
    // const position = editor?.getPosition() as monacoEditor.Position;
    // const { lineNumber, column } = position;
    const selection = editor.getSelection() as monaco.Selection; // 选择的文本范围或光标的当前位置
    const { startLineNumber, startColumn, endLineNumber, endColumn } =
      selection;
    const range = new monaco.Range(
      startLineNumber,
      startColumn,
      endLineNumber,
      endColumn
    );

    return range;
  };

  /** 获取内容 */
  const getValue = () => {
    let value: string = '';
    if (editorRef?.current) {
      const editor = editorRef.current;
      value = editor.getValue();
    }

    return value;
  };

  /** 设置内容 */
  const setValue = (value: any = '') => {
    if (editorRef?.current) {
      const editor = editorRef.current;
      editor.setValue(value);
    }
  };

  /** 撤销 */
  const handleUndoChange = () => {
    if (editorRef?.current) {
      const editor: IEditorEntity = editorRef.current;
      editor.trigger('keyboard', 'undo', null);
      editor.focus();
    }
  };

  /** 重做 */
  const handleRedoChange = () => {
    if (editorRef?.current) {
      const editor: IEditorEntity = editorRef.current;
      editor.trigger('keyboard', 'redo', null);
      editor.focus();
    }
  };

  /** 格式化 */
  const handleFormatChange = useCallback(
    (value?: any) => {
      if (editorRef?.current) {
        const txt = value || getValue();

        setLoading(true);

        formatCodeByLanguage(txt, language).then((res) => {
          setValue(res);
          setLoading(false);
        });
      }
    },
    [language]
  );

  /** 光标处插入文本 */
  const onEditorInsert = (data: string) => {
    if (editorRef.current && data) {
      const editor: IEditorEntity = editorRef.current;
      const range = getMonacoRange(editor);

      // 在光标位置插入文本
      editor?.executeEdits('', [
        {
          range,
          text: data, // 插入的文本
          forceMoveMarkers: true,
        },
      ]);

      // 核心 设置光标的位置
      editor.setPosition({
        lineNumber: range.startLineNumber,
        column: resetEditorPosition(data, range.startColumn + data.length),
      });
      editor.focus(); // 插入完文本 需要聚焦下光标
    }
  };

  /**
   * 获取选中代码内容
   * @returns
   */
  const getEditorSelectionValue = () => {
    let selectedCode = '';
    if (editorRef.current) {
      const editor: IEditorEntity = editorRef.current;
      const range = getMonacoRange(editor);
      const model = editor.getModel();

      selectedCode = model?.getValueInRange(range) ?? '';
    }

    return selectedCode;
  };

  const onEditorRun = () => {
    const val = getEditorSelectionValue();
    console.log(val);
  };

  /**
   * 点击相关事件：插入、撤销、重做等
   * @param event
   */
  const onEditorEvent = (event: IEditorOperateEvent) => {
    const { type, data = '' } = event;

    switch (type) {
      case 'init':
        setValue('');
        onEditorInsert(data);
        break;
      case 'undo':
        handleUndoChange();
        break;
      case 'redo':
        handleRedoChange();
        break;
      case 'insert':
        onEditorInsert(data);
        break;
      case 'run':
        onEditorRun();
        break;
      default:
        break;
    }
  };

  /** editor加载完成后，返回编辑器实例化对象，并赋值到ref */
  const handleOnloadChange = useCallback(
    (editor: IEditorEntity) => {
      editorRef.current = editor;

      if (onLoad) {
        onLoad(editor);
      }
    },
    [onLoad]
  );

  /** 监听输入 */
  const handleCodeChange = useCallback(
    (value: string, event?: any) => {
      setCode(value);

      if (onChange) {
        onChange(value, event as any);
      }
    },
    [onChange]
  );

  /** 将列表更新方法暴露给父组件 */
  useImperativeHandle(handleRef, (): IEditorRefHandles => {
    return {
      getValue: () => getValue(),
      setValue: (value: string) => setValue(value),
      undo: () => handleUndoChange(),
      redo: () => handleRedoChange(),
      insert: (value: string) => onEditorInsert(value),
      run: () => onEditorRun(),
      editorEvent: (event: IEditorOperateEvent) => onEditorEvent(event),
      format: (value?: string) => handleFormatChange(value),
    };
  });

  /** 自定义快捷键 */
  const createCommands = () => {
    if (editorRef?.current) {
      const editor = editorRef.current;
      editor.addAction({
        id: 'run',
        label: 'run',
        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyB],
        run: () => onEditorRun(),
      });

      editor.addAction({
        id: 'save',
        label: 'save',
        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
        run: () => {
          if (saveChange) {
            saveChange();
          }
        },
      });
    }
  };

  useMount(() => {
    createCommands();
  });

  /** 自定义代码提示 */
  useEffect(() => {
    if (editorRef?.current && completers?.length) {
      // 注册
      const registerCompletionInstance = new RegisterCompletion(
        'sql',
        completers
      );

      editorRef?.current?.focus();

      return () => {
        // 销毁
        registerCompletionInstance.dispose();
      };
    }
  }, [completers]);

  useEffect(() => {
    if (format) {
      handleFormatChange();
    }
  }, [handleFormatChange, format]);

  return (
    <EditorContainerLayout>
      <Spin spinning={loading}>
        <MonacoEditor
          language={language}
          theme={theme}
          value={code}
          onChange={handleCodeChange}
          editorDidMount={handleOnloadChange}
          options={{
            selectOnLineNumbers: true,
            roundedSelection: false,
            cursorStyle: 'line',
            autoIndent: 'keep', //自动布局

            theme, // 官方自带三种主题vs, hc-black, or vs-dark
            language, // 语言支持自行查阅demo
            readOnly, // 是否只读
            fontSize,
            overviewRulerBorder: false, // 滚动是否有边框
            scrollBeyondLastLine: false, // 禁用额外滚动区
            automaticLayout: true, // 自动布局
            minimap: {
              enabled: true, // 是否启用预览图
            },
            lineNumbers: 'on', // 控制行号的显隐
            scrollbar: {
              verticalScrollbarSize: 4, // 垂直滚动条宽度，默认px
              horizontalScrollbarSize: 4, // 水平滚动条高度
            },
            contextmenu: true, // 禁用右键菜单
          }}
          {...rest}
        />
      </Spin>
    </EditorContainerLayout>
  );
};